package tchatrmi;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;


/**
 * Tchat en Java RMI
 * @author Toto
 * @version 1.0
 */
public class ServeurImpl extends UnicastRemoteObject implements ServeurInterface {

	private static final long serialVersionUID = -2155717432273508508L;

	/**
	 * Table stockant pour chaque utilisateur, l'url de son objet distant
	 */
	private HashMap<String, ClientInterface> clients;


	/**
	 * 
	 * @throws RemoteException
	 */
	public ServeurImpl() throws RemoteException {
		super();
		clients = new HashMap<String, ClientInterface>();
	}


	/**
	 * 
	 * @throws RemoteException
	 */
	public void enregistrer(String url) throws RemoteException {
		// Recupere une reference (stub) pour le client associe a cette adresse
		ClientInterface client = null;

		try
		{
			client = (ClientInterface) Naming.lookup(url);
		}
		catch(RemoteException e)
		{
			e.printStackTrace();
		} 
		catch (MalformedURLException e) {
			e.printStackTrace();
		} 
		catch (NotBoundException e) {
			e.printStackTrace();
		}

		// Recupere le pseudo de la personne qui entre dans le chat
		String s = client.getUtilisateur();

		synchronized(clients)
		{
			// Ajoute le nom de l'utilisateur et l'URL du client distant
			clients.put(s, client);
		}

		// Envoie un message aux clients distants pour dire qui est entre dans le chat
		envoyerMessage(new Message("Serveur", "nouveau participant : "+s));

		// Envoie un message de bienvenue au nouveau client distant
		envoyerMessageUnique(new Message("Serveur", "Bienvenue "), s);

		// Message de log
		System.out.println(url+" enregistre");
		
		
	}


	/**
	 * 
	 * @throws RemoteException
	 */
	public void desenregistrer(String s) throws RemoteException {

		synchronized(clients)
		{
			// Supprime le client nomm s
			clients.remove(s);
		}

		// Message de log
		System.out.println(s+" supprime");

		// Envoie un message aux clients distants pour dire qui a quitte le chat
		envoyerMessage(new Message("Serveur", s+" est parti"));
	}


	/**
	 * 
	 * @throws RemoteException
	 */
	public ArrayList<String> getUtilisateurs() throws RemoteException {
		ArrayList<String> c = new ArrayList<String>();
		synchronized(clients)
		{
			c.addAll(clients.keySet());
		}
		return c;
	}


	/**
	 * 
	 * @throws RemoteException
	 */
	public synchronized void envoyerMessage(Message m) throws RemoteException
	{
		Iterator<String> iterateur = null;
		ClientInterface client = null;
		String utilisateur = null;

		synchronized(clients)
		{
			// Recuperer l'ensemble des pseudos des clients enregistres
			iterateur = clients.keySet().iterator();
		}

		// Envoie le message a tous les clients distants
		while(iterateur.hasNext())
		{
			// Recupere la ref de l'objet du client
			utilisateur = (String)iterateur.next();

			synchronized(clients)
			{
				client = (ClientInterface) clients.get(utilisateur);
			}

			try {
				// Affiche le message chez le client distant
				client.afficherMessage(m);
			}
			catch(Exception e)
			{
				// Desenregistre un client distant absent
				System.err.println(" utilisateur absent");
				//desenregistrer(utilisateur);//** a finir **//
			}
		}

	}


	/**
	 * 
	 * @throws RemoteException
	 */
	public void envoyerMessageUnique(Message m, String user) throws RemoteException {

		Iterator<String> iterateur = null;
		ClientInterface client = null;
		String utilisateur = null;

		synchronized(clients)
		{
			// Recuperer l'ensemble des pseudos des clients enregistres
			iterateur = clients.keySet().iterator();
		}

		// Parcours des clients
		while(iterateur.hasNext())
		{
			// Recupere la ref de l'objet du client
			utilisateur = (String)iterateur.next();

			if(utilisateur.equals(user)) {
				break;
			}

			utilisateur = null;
		}

		// Si echec du message prive alors on previent l'emetteur
		if((utilisateur == null) && !m.getEmetteur().equals("Serveur"))
		{
			envoyerMessageUnique(new Message("Serveur", utilisateur + " inconnu"), m.getEmetteur());
			return;
		}

		// Cas du serveur
		if(utilisateur == null)
			return;


		// Recuperer une reference pour le client distant associe a cette adresse
		synchronized(clients)
		{
			client = (ClientInterface) clients.get(utilisateur);
		}

		try
		{
			// Affiche le message chez le client distant
			client.afficherMessage(m);
		}
		catch(Exception e)
		{
			// Desenregistre un client distant absent
			System.err.println(" absent");
			//desenregistrer(utilisateur); //a terminer
		}

	}




}
